-- Hex 打印函数
local function to_hex(str)
    local parts = {}
    for i = 1, #str do
        parts[i] = string.format("0x%02X", str:byte(i))
    end
    return table.concat(parts, " ")
end

-- TD 4.3.1 Sink Connect Source Test
baselib.report(0x00, "TD4.3.1 Sink Connect Source Test beginning.")
busilib.ResetOutputs()     -- 恢复到脚本执行前的初始状态
-- 过压保护
busilib.SetProtecter(ADC.VBUS, 3900, 8, 0x40021018, 0x0100, 0)      -- 6V SW.VBUS_GEN GPIOE.8
busilib.SetProtecter(ADC.CC1, 12000, 8, 0x40020418, 0x4000, 0)      -- 5.5V SW.VCONN_GEN GPIOB.14
busilib.SetProtecter(ADC.CC2, 12000, 8, 0x40020418, 0x4000, 0)      -- 5.5V SW.VCONN_GEN GPIOB.14
busilib.setUsbCable(1, 1)
tcpclib.Reinit(1, 0)       -- 重新初始化 TCPC

--[[ 第一步: CVS verifies the PUT does not apply Rp for the remainder of the test. [TD.4.3.1.V.1]  a: 将 CVS 设置成 Disabled.SRC 状态   b: 等待 10ms,待 CC 电压稳定(可选)
c: 正常情况下, 此时 PUT 应该是 sink, CC1 和 CC2 都是下拉, 且已经连接到 CVS, 因此 CVS 在此时测量 CC1 和 CC2 电压, 应该为 0v 左右。执行 CC1 和 CC2 电压测量:
(1) 若 CC1 或 CC2 电压大于 0.25V, 上报检查点 TD.4.3.1.V1 为 FAIL  (2) 若 CC1 和 CC2 电压均小于 0.25v, 上报 TD.4.3.1.V1 为 PASS ]]
-- 第1.a步: set tester to SRC Disabled
busilib.setUsbCcs(1, CCS.Disabled)
busilib.SetRpValue(1, 1)
busilib.setUsbRole(1, ROLE.Source)
-- 第1.b步: 等待电压稳定
baselib.delay(10)                  
-- 第1.c步: 测量 CC1 和 CC2 电压
local VCC1 = busilib.GetADC(ADC.CC1, 4)
local VCC2 = busilib.GetADC(ADC.CC2, 4)
baselib.report(0x00, "测量得到的 CC1 电压为 " .. VCC1 .. "mV, 测量得到的 CC2 电压为 " .. VCC2 .. "mV.")  
if VCC1 > 250 or VCC2 > 250 then   -- 电压应小于0.25V
    baselib.report(0x00, "检查点 TD4.3.1.V.1 fail.")
else
    baselib.report(0x00, "检查点 TD4.3.1.V.1 pass.")
end

-- 第二步: CVS 转换到 Unattached.SRC (原文:CVS transitions to Unattached.SRC)
busilib.setUsbCcs(1, CCS.Unattached)
baselib.report(0x00, "CVS transitions to Unattached.SRC.")
baselib.delay(10) 

--[[ 第三步: (原文)For a PUT_R, CVS terminates one CC pin with Ra in any state other than Disabled for the remainder of the test.
将 CVS 设置成 Unattached.SRC 状态并记录当前时间为 T1,即下面的 Tone ]]
if Captive_Cable then
    busilib.SetSwitchState(SW.CC2_RA, 1)
    baselib.report(0x00, "CVS terminates CC2 pin with Ra.")
    baselib.report(0x00, "CVS wait 50ms ...")
    baselib.delay(50) 
end
local Tone = baselib.get_time()  -- 记录当前时间

--[[ 第四步:(原文)CVS verifies PUT presents Rd for tCCDebounce [TD.4.3.1.V.2]
从T1+100ms 开始, 开始连续N次(暂定N=5,间隔1ms)检测CC1电压处于0.25v - 1.50v之间的, 并设置超时时间为100ms :
(1) 若检测到连续5次满足,上报TD.4.3.1.V2为PASS
(2) 若在100ms都不能连续5次满足,上报TD.4.3.1.V2为FAIL,同时上报最后一次检测到的CC1电压 ]]
--[[ busilib.waitCondition4ad(adc_channel, debonce,lower_limit, upper_limit, times, timeout) 功能: 阻塞脚本, 等待某条件达成。
参数: adc_channel:要监控的 ADC 通道   debounce:采样并去抖次数   lower_limit:目标条件值下限   upper_limit:目标条件值上限   times:目标需要的达成次数   timeout:超时时间,单位为毫秒
返回值: 返回 LuaOk 表示在超时时间内达成目标条件, 返回 LuaTimeout 表示超时 ]]
local waitResult = busilib.waitCondition4ad(ADC.CC1, 4, 200, 1600, 100, 200)
local Tfour = baselib.get_time()
local Tpresent = math.floor((Tfour - Tone) / 1000)
if waitResult == LuaOk then
    baselib.report(0x00, "Rd is presented for at least 100ms within " .. Tpresent .. "ms.")
    baselib.report(0x00, "TD4.3.1.V.2 pass.")
else
    baselib.report(0x00, "Rd presentation timeout.")
    baselib.report(0x00, "TD4.3.1.V.2 fail.")
end

--[[ 第五步:CVS transitions to Attached.SRC 
a. 设置VBUS_GEN = 5.0V   b.上报'PCVS transitions to Attached.SRC   c.记录时间为T6 ]]
busilib.preparePower(1, 1, 5000)    -- 准备 VBus 电压
busilib.preparePower(1, 0, 3300)    -- 准备 VConn 电压
busilib.setUsbCcs(1, CCS.Attached)
baselib.report(0x00, "PCVS transitions to Attached.SRC.")
local Tsix = baselib.get_time()

-- 第六步: CVS verifies that PUT transitions to Attached.SNK
-- 第6.a步: If PUT data connection before PD contract, verify PUT sinks current according to CVS advertisement. [TD.4.3.1.V.3]
-- 这一步应该还写不了

-- 第6.b步: If PUT supports PD:PUT and CVS negotiate an explicit contract. [TD.4.3.1.V.4]
-- 如果PUT支持PD,CVS和PUT协商PD协议
local function PDcheck( ... )
    if USB_PD_Support then
        baselib.report(0x00, "Begin power negotiation.")
        tcpclib.SetPermission(1, 2)
        -- 清空 PD Rx 堆栈
        while tcpclib.PDRxCnt(1, 0) ~= 0 do
            local message, time = tcpclib.PDRxMsg(1, 0)
            baselib.report(0x00, "Unsolved PD message: " .. to_hex(message) .. " at " .. math.floor(time/1000) .. "ms.")
        end
        -- Send Source Capabilities
        ret = tcpclib.SendPD(1, 0, 0, 0,
            string.char(0xA1, 0x51,
            0xC8, 0x90, 0x01, 0x0A, 0xC8, 0xD0, 0x02, 0x00,
            0xC8, 0xC0, 0x03, 0x00, 0x2C, 0xB1, 0x04, 0x00,
            0x45, 0x41, 0x06, 0x00),
            2, 1000, 1000)
        if ret == LuaOk then
            baselib.report(0x00, "Source capabilities message sent successfully.")
            local wait_cnt = 0
            while tcpclib.PDRxCnt(1, 0) == 0 do     -- 等待接收PD消息
                baselib.delay(5)
                wait_cnt = wait_cnt + 1
                if wait_cnt >= 100 then             -- 500ms 内没收到任何 PD 消息
                    baselib.report(0x00, "Request Rx timeout, The test was forced to terminate!")
                    baselib.report(0x00, "TD4.3.1.V.4 fail.")
                    return false
                end
            end
        else
            baselib.report(0x00, "PD message send failed: error " .. ret .. ".")
            baselib.report(0x00, "TD4.3.1.V.4 fail.")
            return false
        end
        -- 处理收到的 PD 消息
        while tcpclib.PDRxCnt(1, 0) ~= 0 do
            local message, time = tcpclib.PDRxMsg(1, 0)
            baselib.report(0x00, "Received PD message: " .. to_hex(message) .. " at " .. math.floor(time/1000) .. "ms.")
            if (message:byte(1) & 0x0F) == 0x02 then    -- 是请求电源的消息
                baselib.report(0x00, "Received Request message, the test was successfully ended!")
                baselib.report(0x00, "TD4.3.1.V.4 pass.")
                -- 象征性同意一下，但不加电、不回复 PsRdy
                ret = tcpclib.SendPD(1, 1, 0, 0,
                    string.char(0x63, 0x03),
                    2, 1000, 1000)
                goto PN_end
            end
        end
        -- 收到的都不是 Request 消息，测试失败
        baselib.report(0x00, "TD4.3.1.V.4 fail.")
        return false
    end

    :: PN_end :: 
    -- 清空未处理 PD 消息
    while tcpclib.PDRxCnt(1, 0) ~= 0 do
            local message, time = tcpclib.PDRxMsg(1, 0)
            baselib.report(0x00, "Unsolved PD message: " .. to_hex(message) .. " at " .. math.floor(time/1000) .. "ms.")
        end
        -- 发送 Discover ID 消息给 SOP
        ret = tcpclib.SendPD(1, 2, 0, 0,
            string.char(0x6F, 0x15, 0x01, 0x80, 0x00, 0xFF),
            2, 1000, 1000)   
        -- 判断是否发送成功，并等待 SOP 回复 ACK
        if ret == LuaOk then
            baselib.report(0x00, "Discover ID message sent successfully.")
            baselib.report(0x00, "TD.4.3.1.V.9 pass.")
            local wait_cnt = 0
            while tcpclib.PDRxCnt(1, 0) == 0 do
                baselib.delay(5)
                wait_cnt = wait_cnt + 1
                if wait_cnt >= 200 then
                    baselib.report(0x00, "DID ACK message Rx timeout, The test was forced to terminate!")
                goto script_end
                end
            end
        else
            baselib.report(0x00, "PD message send failed: error " .. ret .. ".")
            baselib.report(0x00, "TD.4.3.1.V.9 fail.")
            goto script_end
        end
        -- 判断 SOP 回复 ACK
        while tcpclib.PDRxCnt(1, 0) ~= 0 do
            local message, time = tcpclib.PDRxMsg(1, 0)
            baselib.report(0x00, "Received PD message: " .. to_hex(message) .. " at " .. math.floor(time/1000) .. "ms.")
            if (message:byte(1) & 0x0F) == 0x0F     -- Vendor Defined Message
                and (message:byte(2) & 0x70) >= 0x10   -- Number of Data Objects >= 1
                and (message:byte(4) & 0x80) == 0x80    -- Structured VDM
                and (message:byte(3) & 0xDF) == 0x41    -- Discover Identity ACK
            then   
                baselib.report(0x00, "Received DID ACK message, the test was successfully ended!")
                baselib.report(0x00, "TD.4.3.1.V.10 pass.")
            goto script_end
            end
        end 
    :: script_end ::
    return true
end

-- 第6.c步: If PUT supports USB 3.1 UFP: i: PUT starts data communications on its SuperSpeed pairs. [TD.4.3.1.V.5]
-- ii: After eSS terminations are applied, and prior to PD Enter Mode negotiation if applicable, the SBU pins on the PUT are within zSBUTermination [TD.4.3.1.V.6]
--默认不支持 USB 3.1 UFP, 直接跳过

-- 第d: Else if PUT supports USB 2.0 UFP: PUT starts data communications on its D+/D- pair [TD.4.3.1.V.7]
-- 缺少这一步

local max_attempts = 8
for i = 1, max_attempts do
    -- Perform PD check immediately in each iteration
    if PDcheck() then
        baselib.report(0x00, string.format("PD check PASSED (Attempt %d/%d)", i, max_attempts))
        break
    end
    -- Report current attempt status
    baselib.report(0x00, string.format("PD check FAILED (Attempt %d/%d)", i, max_attempts))
    -- Handle waiting and final attempt differently
    if i < max_attempts then
        baselib.delay(100)
        baselib.report(0x00, "Waiting 100ms before retry...")
    else
        baselib.report(0x00, "MAX ATTEMPTS REACHED - PD check failed after 8 retries")
    end
end

-- 第6.e步: For a PUT_R, VCONN is not supplied [TD.4.3.1.V.8]  注: if VCONN voltage is lower than 3.0V
if Captive_Cable then
    VCC2 = busilib.GetADC(ADC.CC2, 8)
    baselib.report(0x00, "测量得到 CC2 电压为 " .. VCC2 .. "mV.")
    if VCC2 < 3000 then
        baselib.report(0x00, "TD4.3.1.V.8 pass.")
    else
        baselib.report(0x00, "TD4.3.1.V.8 fail.")
    end
end

-- 第8.b步: PUT Remains in Attached.SNK during and for 500ms after step 6. [TD.4.3.1.V.11]
local monitor1 = busilib.newMonitor(TMD.TIME_LIST, 0, {1}, {500000}, {0})
local monitor1result = busilib.waitMonitor(monitor1, 600)
busilib.deleteMonitor(monitor1)
if monitor1result ~= 1 then
    VCC1 = busilib.GetADC(ADC.CC1, 8)
    baselib.report(0x00, "TD.4.3.1.V.11 fail, CC1 is " .. VCC1 .. "mV.")
else
    baselib.report(0x00, "The PUT remains in the Attached state for more than 500ms.")
    baselib.report(0x00, "TD.4.3.1.V.11 pass.")
end

-- 第九步: CVS programs Vbus source to meet 3.7V at the PUT connector   CVS将VBUS电压设置为3.7V
busilib.preparePower(1, 1, 3700)   
baselib.report(0x00, "CVS 已将 VBus 电压设置为3.7V.")

-- 第十步: CVS verifies PUT remains in Attached.SNK
-- 10.a: PUT maintains Rd on its CC [TD.4.3.1.V.12]
local VCC1 = busilib.GetADC(ADC.CC1, 4)
if VCC1 >= 250 and VCC1 <= 2040 then
    baselib.report(0x00, "TD.4.3.1.V.12 pass.")
else
    baselib.report(0x00, "TD.4.3.1.V.12 fail.")
end
-- 10.b: For a PUT that supports USB 3.2 or USB 2.0 signaling, the data signaling is maintained. [TD.4.3.1.V.13]
-- 这一步赵工正在弄

-- 第十一步: CVS removes Rps. CVS USB 2.0 and USB 3.1 signaling behaves as though it is in Attached.SRC as long as PUT is in Attached.SNK
busilib.SetSwitchState(SW.CC1_RP_0A5, 0)  -- 断开CC1的Rp
-- 后半句应该还写不了

--[[ 第十二步: CVS decreases Vbus voltage by 0.1V  a: Wait 100ms  b: If PUT removes Rd, or a PUT that supports USB 3.2 or USB 2.0 signaling 
ceases signaling, or Vbus source voltage is below 800mV, continue to step 13    d. Continue to step 12 ]]
baselib.report(0x00, "CVS 开始降低 VBus 输出.")
local VBusValue = 3700
while true do
    VBusValue = VBusValue - 100 
    busilib.preparePower(1, 1, VBusValue)  
    baselib.delay(100)
    local VBUS = busilib.GetADC(ADC.VBUS, 4) 
    -- 12.b: 判断条件: a PUT that supports USB 3.2 or USB 2.0 signaling ceases signaling 不会写
    if VBUS < 800 then    -- 如果VBUS电压低于800mV，直接跳出循环
        baselib.report(0x00, "CVS VBus 电压降低到 " .. VBusValue .. "mV.结束第十一步")
        break
    end  
end

-- 第十三步: CVS verifies that all data signaling ceases [TD.4.3.1.V.14]
-- 不会写

-- 第十四步: CVS applies Rp
busilib.SetSwitchState(SW.CC1_RP_0A5, 1) 

-- 第十五步: If Vbus is below 800 mV, continue to step 18
local VBUS = busilib.GetADC(ADC.VBUS, 4)
if VBUS >= 800 then
    -- 第十六步: CVS verifies PUT remains in AttachWait.SNK for 500ms [TD.4.3.1.V.15]
    local AttachedWait_maintained = busilib.waitCondition4ad(ADC.CC1, 4, 250, 2040, 5, 500) 
    if AttachedWait_maintained == LuaOk then  -- Rp持续超过 500ms，判断 PUT 仍然处于 AttachWait.SRC
        baselib.report(0x00, "TD.4.3.1.V.15 pass.")
    end
    -- 第十七步: CVS removes Vbus source
    -- 有专门函数吗？
end

-- 第十八步: CVS transitions to Disabled , CVS最终状态恢复为Disabled
busilib.setUsbCcs(1, CCS.Disabled)

-- 第十九步: CVS verifies that PUT transitions to Unattached.SNK before tVBUSOFF expires: PUT data communication has ceased. [TD.4.3.1.V.16]

-- 第二十步: CVS waits 1 second
busilib.delay(1000)  

-- 脚本即将结束
busilib.ResetOutputs()
tcpclib.SetPermission(1, 0)
baselib.report(0x00, "Demo is done here.")
baselib.report(0x07, "\x04")
